package me.zhengjie.minbearwcs.listener.agv.action;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDetailDao;
import me.zhengjie.minbearwcs.dao.mission.inf.WcsMissionDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundStockUpRecordDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundTaskRecordDao;
import me.zhengjie.minbearwcs.dao.storage.inf.LargeStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.MediumStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.StorageDao;
import me.zhengjie.minbearwcs.entity.DTO.agv.TUSK.TUSKFeedBackTask;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvContentPool;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvMission;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvMissionDetail;
import me.zhengjie.minbearwcs.entity.PO.agv.missionEnum.AgvMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.type.MissionType;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.OutboundStockUpRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.PalletMediumStorageSearchPo;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.LargeStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.MediumStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.type.StorageType;
import me.zhengjie.minbearwcs.utils.JsonUtil;
import me.zhengjie.minbearwcs.utils.LogFileKey;
import me.zhengjie.observer.event.IWcsEvent;
import me.zhengjie.observer.listener.IWcsEventListener;
import me.zhengjie.observer.type.WcsEventType;
import me.zhengjie.observer.type.agv.AgvActionEventType;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class GetActionListener implements IWcsEventListener {

    private final AgvMissionDetailDao agvMissionDetailDao;
    private final AgvMissionDao agvMissionDao;
    private final SmallStorageDao smallStorageDao;
    private final StorageDao storageDao;
    private final WcsMissionDao wcsMissionDao;
    private final OutboundStockUpRecordDao outboundStockUpRecordDao;
    private final MediumStorageDao mediumStorageDao;
    private final OutboundTaskRecordDao outboundTaskRecordDao;
    private final LargeStorageDao largeStorageDao;


    @Override
    @Transactional
    public void onEvent(IWcsEvent wcsEvent) {
        MDC.put(LogFileKey.KEY, LogFileKey.Module.AGV);


        TUSKFeedBackTask feedBackEvent = (TUSKFeedBackTask) wcsEvent.getSource();

        log.info("获取到agv上报GET信息：{}", JsonUtil.getJsonInfo(feedBackEvent));
        /**
         *
         * 1.更新 agv任务明细
         * 2.更新agv任务
         * 3.清空储位栈板号
         * 4.更新wcs任务状态
         */

        //1.更新 agv任务明细
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByTaskIdAndPoint(feedBackEvent.getTaskId(), feedBackEvent.getTargetPoint());
        agvMissionDetailDao.updateMarkTimeAndIsCompleteById(
                agvMissionDetail.getId(),
                LocalDateTime.now(),
                AgvContentPool.AGV_ACTION_COMPLETE
        );

        //2.更新agv任务
        agvMissionDao.updateAgvMissionBegin(
                feedBackEvent.getTaskId(),
                AgvMissionStatus.PROCESSING,
                agvMissionDetail.getTaskIndex(),
                feedBackEvent.getAgvNo(),
                LocalDateTime.now()
        );

        // 3.清空储位栈板号
        MissionType wcsMissionType = agvMissionDao.selectWcsMissionTypeByTaskId(feedBackEvent.getTaskId());
        switch (wcsMissionType) {
            case INBOUND_3_OR_4_FLOOR:
                smallStorageDao.clearStoragePallet(feedBackEvent.getTargetPoint());
                break;
            case INBOUND_5_OR_6_FLOOR:
                smallStorageDao.clearStoragePallet(feedBackEvent.getTargetPoint());
                break;
            case OUTBOUND_STOCK_UP:
                outboundStockUpGet(feedBackEvent);
                break;
            case OUTBOUND_WHOLE_PALLET:
                outboundWholePalletGet(feedBackEvent);
                break;
            case OUTBOUND_SORT:
                outboundSortGet(feedBackEvent);
                break;
            case OUTBOUND_AFTER_SORT:
                smallStorageDao.clearStoragePallet(feedBackEvent.getTargetPoint());
                break;
            case SHIFTING:
            case REWORK_SHIFTING:
            case REWORK:
                shiftingGet(feedBackEvent);
                break;
        }

        MDC.remove(LogFileKey.Module.AGV);
    }

    private void shiftingGet(TUSKFeedBackTask feedBackEvent){
        String targetPoint = feedBackEvent.getTargetPoint();
        smallStorageDao.clearStoragePallet(targetPoint);
        judgeAndClearMediumStorage(targetPoint);
    }


    private void outboundStockUpGet(TUSKFeedBackTask feedBackEvent) {
        String targetPoint = feedBackEvent.getTargetPoint();
        StorageType storageType = storageDao.selectLargeStorageTypeBySmallStorageCode(targetPoint);

        if (StorageType.MANTISSA_AREA_5F == storageType) {
            smallStorageDao.clearStoragePallet(targetPoint);
        } else {
            AgvMission agvMission = agvMissionDao.selectByTaskId(feedBackEvent.getTaskId());
            String associatedDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(agvMission.getWcsMissionId());
            OutboundStockUpRecord outboundStockUpRecord = outboundStockUpRecordDao.selectByStockUpId(associatedDetailId);
            if (outboundStockUpRecord.getOutboundOrderCode() == null) {
                smallStorageDao.clearStoragePallet(targetPoint);
                judgeAndClearMediumStorage(targetPoint);
            } else {
                smallStorageDao.onlyCLearPalletCode(targetPoint);
            }

        }

    }


    private void outboundSortGet(TUSKFeedBackTask feedBackEvent) {
        String targetPoint = feedBackEvent.getTargetPoint();

        smallStorageDao.clearStoragePallet(targetPoint);
        judgeAndClearMediumStorage(targetPoint);

    }

    // 清除小储位后，清理中储位物料信息
    private void judgeAndClearMediumStorage(String smallStorageCode) {
        SmallStorage smallStorage = smallStorageDao.selectBySmallStorage(smallStorageCode);
        MediumStorage mediumStorage = mediumStorageDao.selectByMediumStorage(smallStorage.getMediumStorageCode());
        LargeStorage largeStorage = largeStorageDao.selectByLargeStorageCode(mediumStorage.getLargeStorageCode());

        if (StorageType.STORAGE_AREA_5F != largeStorage.getLargeStorageType() &&
                StorageType.STORAGE_AREA_6F != largeStorage.getLargeStorageType()) return;

        List<PalletMediumStorageSearchPo> palletMediumStorageSearchPoList = storageDao.selectPalletOrOutboundFreezePalletMediumStorage(smallStorage.getMediumStorageCode());

        Map<String, Long> collect = palletMediumStorageSearchPoList.stream()
                .map(a -> a.getMaterialCode() + a.getInboundOrderCode() + a.getBatchCode())
                .collect(Collectors.groupingBy(a -> a, Collectors.counting()));


        String mediumMaterial1 = mediumStorage.getMaterialOne() + mediumStorage.getInboundOrderOne() + mediumStorage.getBatchOne();
        String mediumMaterial2 = mediumStorage.getMaterialTwo() + mediumStorage.getInboundOrderTwo() + mediumStorage.getBatchTwo();

        Long num1 = collect.getOrDefault(mediumMaterial1,0l);
        Long num2 = collect.getOrDefault(mediumMaterial2,0l);

        if (num1 == 0l) {
            mediumStorageDao.updateBatch1Info(smallStorage.getMediumStorageCode(), null, null, null);
        }

        if (num2 == 0l) {
            mediumStorageDao.updateBatch2Info(smallStorage.getMediumStorageCode(), null, null, null);
        }
    }

    private void outboundWholePalletGet(TUSKFeedBackTask feedBackEvent) {
        String targetPoint = feedBackEvent.getTargetPoint();
        StorageType storageType = storageDao.selectLargeStorageTypeBySmallStorageCode(targetPoint);

        switch (storageType) {
            case WAIT_SORT_AREA_5F:
            case WAIT_SORT_AREA_6F:
                smallStorageDao.clearStoragePallet(targetPoint);
                clearWaitSortAreaMediumOutboundOrder(targetPoint);
                break;
            case STORAGE_AREA_5F:
            case STORAGE_AREA_6F:
                smallStorageDao.onlyCLearPalletCode(targetPoint);
                break;
        }
    }


    private void clearWaitSortAreaMediumOutboundOrder(String targetPoint) {
        SmallStorage smallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        Integer numInMediumStorage = storageDao.selectPalletNumInMediumStorage(smallStorage.getMediumStorageCode());
        if (numInMediumStorage == 0) {
            mediumStorageDao.updateOutboundOrderByMediumStorage(
                    smallStorage.getMediumStorageCode(),
                    null
            );
        }

    }


    @Override
    public WcsEventType getEventType() {
        return AgvActionEventType.GET;
    }
}
